import { Injectable } from '@nestjs/common';
import { CreateTournamentDto } from './dto/create-tournament.dto';
import { UpdateTournamentDto } from './dto/update-tournament.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Tournament } from './entities/tournament.entity';
import { Repository } from 'typeorm/repository/Repository';
import logger from 'src/common/utils/log';
import {
  CategoryStatusEnum,
  TournamentStatusEnum,
} from 'src/common/constant/enums';

@Injectable()
export class TournamentService {
  constructor(
    @InjectRepository(Tournament)
    private repository: Repository<Tournament>,
  ) {}
  async create(createTournamentDto: CreateTournamentDto) {
    const entity = this.repository.create(createTournamentDto);
    return await this.repository.save(entity);
  }

  async findAll() {
    return await this.repository.find({
      order: {
        createTime: 'DESC',
      },
    });
  }

  async findDetailById(id: number) {
    // return await this.repository.find({ where: { id } });
    const res = await this.repository
      .createQueryBuilder('tournament')
      .where('tournament.id = :id', { id: id })
      .leftJoinAndSelect('tournament.categories', 'category')
      .leftJoinAndSelect('category.events', 'events')
      .leftJoinAndSelect('events.stages', 'stages')
      .leftJoinAndSelect('stages.groups', 'groups')
      .leftJoinAndSelect('stages.stageEvents', 'stageEvents')
      .getOne();
    return res;
  }

  async findForPlayerSignupExport(id: number) {
    // return await this.repository.find({ where: { id } });
    const res = await this.repository
      .createQueryBuilder('tournament')
      .where('tournament.id = :id', { id: id })
      .leftJoinAndSelect('tournament.categories', 'category')
      .leftJoinAndSelect('category.events', 'events')
      .leftJoinAndSelect('events.stages', 'stages')
      .leftJoinAndSelect('events.playerSignups', 'playerSignups')
      .leftJoinAndSelect('stages.groups', 'groups')
      .leftJoinAndSelect('stages.stageEvents', 'stageEvents')
      .getOne();
    return res;
  }

  async findTournamentForDelete(id: number) {
    const res = await this.repository
      .createQueryBuilder('tournament')
      .where('tournament.id = :id', { id: id })
      .leftJoinAndSelect('tournament.categories', 'category')
      .leftJoinAndSelect('category.events', 'events')
      .leftJoinAndSelect('events.eventToPlayers', 'eventToPlayers')
      .leftJoinAndSelect('events.playerSignups', 'playerSignups')
      .getOne();
    return res;
  }

  async update(id: number, updateTournamentDto: UpdateTournamentDto) {
    await this.repository.update(id, updateTournamentDto);
    return await this.repository.find({ where: { id } });
  }

  async remove(id: number) {
    return await this.repository.delete(id);
  }
  async findByCreateBy(createBy: number) {
    return await this.repository.find({
      where: { createBy: createBy },
      order: { createTime: 'DESC' },
    });
  }
  async removeInIds(ids: number[]) {
    return await this.repository.delete(ids);
  }
  async removeIds(ids: number[]) {
    return await this.removeInIds(ids);
  }
  async getByIdWithCategories(id: number) {
    return await this.repository.findOne({
      where: { id },
      relations: ['categories'],
    });
  }

  async checkFinish(id: number) {
    logger.info('finishTournament...', id);
    const { categories } = await this.getByIdWithCategories(id);
    const isAllFinished = categories.every(
      (category) => category.status === CategoryStatusEnum.Finished,
    );
    if (isAllFinished) {
      await this.update(id, {
        status: TournamentStatusEnum.Finished,
      });
    }
    logger.info('finishTournament...', id, isAllFinished);
    return isAllFinished;
  }

  async searchTournaments(
    name: string | null,
    status: TournamentStatusEnum | null,
    page: number,
    limit: number,
  ) {
    const queryBuilder = this.repository.createQueryBuilder('tournament');

    if (name) {
      queryBuilder.where('tournament.name LIKE :name', { name: `%${name}%` });
    }

    if (status) {
      if (name) {
        queryBuilder.andWhere('tournament.status = :status', { status });
      } else {
        queryBuilder.where('tournament.status = :status', { status });
      }
    }

    const skip = (page - 1) * limit;
    queryBuilder.skip(skip).take(limit);

    const [tournaments, total] = await queryBuilder.getManyAndCount();

    return {
      records: tournaments,
      total,
      current: page,
      size: limit,
    };
  }
}
